{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Decorators Application (Timing)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here we go back to an example we have seen in the past - timing how long it takes to run a certain function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def timed(fn):\n",
    "    from time import perf_counter\n",
    "    from functools import wraps\n",
    "    \n",
    "    @wraps(fn)\n",
    "    def inner(*args, **kwargs):\n",
    "        start = perf_counter()\n",
    "        result = fn(*args, **kwargs)\n",
    "        end = perf_counter()\n",
    "        elapsed = end - start\n",
    "        \n",
    "        args_ = [str(a) for a in args]\n",
    "        kwargs_ = ['{0}={1}'.format(k, v) for (k, v) in kwargs.items()]\n",
    "        all_args = args_ + kwargs_\n",
    "        args_str = ','.join(all_args)\n",
    "        print('{0}({1}) took {2:.6f}s to run.'.format(fn.__name__, \n",
    "                                                         args_str,\n",
    "                                                         elapsed))\n",
    "        return result\n",
    "    \n",
    "    return inner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's write a function that calculates the n-th Fibonacci number:\n",
    "\n",
    "`1, 1, 2, 3, 5, 8, ...`\n",
    "\n",
    "We will implement this using three different methods:\n",
    "1. recursion\n",
    "2. a loop\n",
    "3. functional programming (reduce)\n",
    "\n",
    "We use a 1-based system, e.g. first Fibonnaci number has index 1, etc."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Using Recursion\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def calc_recursive_fib(n):\n",
    "    if n <=2:\n",
    "        return 1\n",
    "    else:\n",
    "        return calc_recursive_fib(n-1) + calc_recursive_fib(n-2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "calc_recursive_fib(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "calc_recursive_fib(6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "@timed\n",
    "def fib_recursed(n):\n",
    "    return calc_recursive_fib(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_recursed(33) took 1.060477s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3524578"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_recursed(33)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_recursed(34) took 1.715229s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "5702887"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_recursed(34)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_recursed(35) took 2.773638s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9227465"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_recursed(35)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There's a reason we did not decorate our recursive function directly!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "@timed\n",
    "def fib_recursed_2(n):\n",
    "    if n <=2:\n",
    "        return 1\n",
    "    else:\n",
    "        return fib_recursed_2(n-1) + fib_recursed_2(n-2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000001s to run.\n",
      "fib_recursed_2(3) took 0.000409s to run.\n",
      "fib_recursed_2(2) took 0.000001s to run.\n",
      "fib_recursed_2(4) took 0.000460s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000038s to run.\n",
      "fib_recursed_2(5) took 0.000535s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000038s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(4) took 0.000075s to run.\n",
      "fib_recursed_2(6) took 0.000646s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000036s to run.\n",
      "fib_recursed_2(2) took 0.000001s to run.\n",
      "fib_recursed_2(4) took 0.000071s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000035s to run.\n",
      "fib_recursed_2(5) took 0.000143s to run.\n",
      "fib_recursed_2(7) took 0.000837s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000001s to run.\n",
      "fib_recursed_2(3) took 0.000036s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(4) took 0.000072s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000036s to run.\n",
      "fib_recursed_2(5) took 0.000142s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000037s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(4) took 0.000073s to run.\n",
      "fib_recursed_2(6) took 0.000251s to run.\n",
      "fib_recursed_2(8) took 0.001125s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000041s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(4) took 0.000076s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000035s to run.\n",
      "fib_recursed_2(5) took 0.000146s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000001s to run.\n",
      "fib_recursed_2(3) took 0.000036s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(4) took 0.000072s to run.\n",
      "fib_recursed_2(6) took 0.000253s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000001s to run.\n",
      "fib_recursed_2(3) took 0.000048s to run.\n",
      "fib_recursed_2(2) took 0.000001s to run.\n",
      "fib_recursed_2(4) took 0.000085s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000036s to run.\n",
      "fib_recursed_2(5) took 0.000156s to run.\n",
      "fib_recursed_2(7) took 0.000444s to run.\n",
      "fib_recursed_2(9) took 0.001604s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000001s to run.\n",
      "fib_recursed_2(3) took 0.000036s to run.\n",
      "fib_recursed_2(2) took 0.000001s to run.\n",
      "fib_recursed_2(4) took 0.000071s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000036s to run.\n",
      "fib_recursed_2(5) took 0.000142s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000036s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(4) took 0.000071s to run.\n",
      "fib_recursed_2(6) took 0.000248s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000040s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(4) took 0.000075s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000036s to run.\n",
      "fib_recursed_2(5) took 0.000145s to run.\n",
      "fib_recursed_2(7) took 0.000429s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000035s to run.\n",
      "fib_recursed_2(2) took 0.000001s to run.\n",
      "fib_recursed_2(4) took 0.000075s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000035s to run.\n",
      "fib_recursed_2(5) took 0.000145s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(1) took 0.000000s to run.\n",
      "fib_recursed_2(3) took 0.000041s to run.\n",
      "fib_recursed_2(2) took 0.000000s to run.\n",
      "fib_recursed_2(4) took 0.000076s to run.\n",
      "fib_recursed_2(6) took 0.000256s to run.\n",
      "fib_recursed_2(8) took 0.000720s to run.\n",
      "fib_recursed_2(10) took 0.002367s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "55"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_recursed_2(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since we are calling the function recursively, we are actually calling the **decorated** function recursively. In this case I wanted the total time to calculate the n-th number, not the time for each recursion.\n",
    "\n",
    "You will notice from the above how inefficient the recursive method is: the same fibonacci numbers are calculated repeatedly! This is why as the value of `n` start increasing beyond 30 we start seeing considerable slow downs."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Using a Loop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "@timed\n",
    "def fib_loop(n):\n",
    "    fib_1 = 1\n",
    "    fib_2 = 1\n",
    "    for i in range(3, n+1):\n",
    "        fib_1, fib_2 = fib_2, fib_1 + fib_2\n",
    "    return fib_2               "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_loop(3) took 0.000003s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_loop(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_loop(6) took 0.000002s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_loop(6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_loop(34) took 0.000004s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "5702887"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_loop(34)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_loop(35) took 0.000005s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9227465"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_loop(35)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see this method is much more efficient!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Using  Reduce"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We first need to understand how we are going to calculate the Fibonnaci sequence using reduce: \n",
    "\n",
    "<pre>\n",
    "n=1:\n",
    "(1, 0) --> (1, 1)\n",
    "\n",
    "n=2:\n",
    "(1, 0) --> (1, 1) --> (1 + 1, 1) = (2, 1)  : result = 2 \n",
    "\n",
    "n=3\n",
    "(1, 0) --> (1, 1) --> (2, 1) --> (2+1, 2) = (3, 2)  : result = 3\n",
    "\n",
    "n=4\n",
    "(1, 0) --> (1, 1) --> (2, 1) --> (3, 2) --> (5, 3)  : result = 5\n",
    "</pre>\n",
    "\n",
    "In general each step in the reduction is as follows:\n",
    "\n",
    "<pre>\n",
    "previous value = (a, b)\n",
    "new value = (a+b, a)\n",
    "</pre>\n",
    "\n",
    "If we start our reduction with an initial value of `(1, 0)`, we need to run our \"loop\" n times.\n",
    "\n",
    "We therefore use a \"dummy\" sequence of length `n` to create `n` steps in our reduce.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "\n",
    "@timed\n",
    "def fib_reduce(n):\n",
    "    initial = (1, 0)\n",
    "    dummy = range(n-1)\n",
    "    fib_n = reduce(lambda prev, n: (prev[0] + prev[1], prev[0]), \n",
    "                   dummy, \n",
    "                   initial)\n",
    "    return fib_n[0]                  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_reduce(3) took 0.000004s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_reduce(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_reduce(6) took 0.000005s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_reduce(6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_reduce(34) took 0.000013s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "5702887"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_reduce(34)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_reduce(35) took 0.000014s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9227465"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_reduce(35)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can run a quick comparison between the various timed implementations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_recursed(35) took 2.771373s to run.\n",
      "fib_loop(35) took 0.000007s to run.\n",
      "fib_reduce(35) took 0.000013s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9227465"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_recursed(35)\n",
    "fib_loop(35)\n",
    "fib_reduce(35)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Even though the recursive algorithm is by far the easiest to understand, it is also the slowest. We'll see how to fix this in an upcoming video using a technique called **memoization**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First let's focus on the loop and reduce variants. Our timing is not very effective since we only time a single calculation for each - there could be some variance if we run these tests multiple times:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_loop(10000) took 0.002114s to run.\n",
      "fib_loop(10000) took 0.002109s to run.\n",
      "fib_loop(10000) took 0.002072s to run.\n",
      "fib_loop(10000) took 0.002072s to run.\n",
      "fib_loop(10000) took 0.002075s to run.\n",
      "fib_loop(10000) took 0.002078s to run.\n",
      "fib_loop(10000) took 0.002049s to run.\n",
      "fib_loop(10000) took 0.002064s to run.\n",
      "fib_loop(10000) took 0.002533s to run.\n",
      "fib_loop(10000) took 0.002109s to run.\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "    result =  fib_loop(10000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_reduce(10000) took 0.004234s to run.\n",
      "fib_reduce(10000) took 0.003961s to run.\n",
      "fib_reduce(10000) took 0.004363s to run.\n",
      "fib_reduce(10000) took 0.004459s to run.\n",
      "fib_reduce(10000) took 0.003895s to run.\n",
      "fib_reduce(10000) took 0.003847s to run.\n",
      "fib_reduce(10000) took 0.004342s to run.\n",
      "fib_reduce(10000) took 0.003908s to run.\n",
      "fib_reduce(10000) took 0.003970s to run.\n",
      "fib_reduce(10000) took 0.003970s to run.\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "    result = fib_reduce(10000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In general it is better to time the same function call multiple times and generate and average of the run times.\n",
    "\n",
    "We'll see in an upcoming video how we can do this from within our decorator."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the meantime observe that the simple loop approach seems to perform about twice as fast as the reduce approach!!\n",
    "\n",
    "The moral of this side note is that simply because you **can** do something in  Python using some fancy or cool technique does not mean you **should**!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We technically could write our reduce-based function as a one liner:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from functools import reduce \n",
    "\n",
    "fib_1 = timed(lambda n: reduce(lambda prev, n: (prev[0] + prev[1], prev[0]),\n",
    "                               range(n), \n",
    "                               (0, 1))[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fib_loop(100) took 0.000009s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "354224848179261915075"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_loop(100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<lambda>(100) took 0.000031s to run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "354224848179261915075"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fib_1(100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So yes, it's cool that you can write this using a single line of code, but consider two things here:\n",
    "1. Is it as efficient as another method?\n",
    "2. Is the code **readable**?\n",
    "\n",
    "Code readability is something I cannot emphasize enough. Given similar efficiencies (cpu / memory), give preference to code that is more easily understandable!\n",
    "\n",
    "Sometimes, if the efficiency is not greatly impacted (or does not matter in absolute terms), I might even give preference to less efficient, but more readable (i.e. understanbdable), code.\n",
    "\n",
    "But enough of the soapbox already :-)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
